'''
测试各种初始化性能，描点
'''

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import math
import random
import os
import copy
from scipy.stats import norm


def drawChart(X, pop):
    plt.figure(num=1, figsize=(14, 7))
    plt.subplot(1, 2, 1)
    a = []
    b = []
    for i in range(pop):
        a.append(i)
        b.append(X[i])
    plt.xlabel('维度值')
    plt.ylabel('混沌值')
    plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
    plt.rcParams['axes.unicode_minus'] = False
    plt.legend()
    plt.scatter(a, b)
    plt.subplot(1, 2, 2)
    plt.xlabel('混沌值')
    plt.ylabel('帧数')
    plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
    plt.rcParams['axes.unicode_minus'] = False
    plt.legend()

    plt.hist(X)
    plt.show()


'''普通随机初始化'''


def ordinaryMap(pop, dim, ub, lb,obj_func=None):
    X = np.zeros([pop, dim])
    for i in range(pop):
        for j in range(dim):
            X[i, j] = np.random.random() * (ub[j] - lb[j]) + lb[j]
    rX = np.zeros([pop, dim])
    for i in range(pop):
        for j in range(dim):
            rX[i, j] = lb[j] + ub[j] - X[i, j]
    newX = np.zeros([pop * 2, dim])
    for i in range(pop * 2):
        if i < pop:
            newX[i] = X[i]
        else:
            newX[i] = rX[i - pop]
    fitness = np.zeros([2 * pop, 1])
    for i in range(pop * 2):
        fitness[i] = obj_func(newX[i])

    allY, index = SortFitness(fitness)
    allX = SortPosition(index, newX, pop, dim)

    return allX[:pop], allY[:pop]



'''混沌映射Logistic'''


def logisticMap(pop, dim, ub, lb):
    r = 4.0  # [0，4]
    Z = np.zeros([pop, dim])
    Z[0, :] = np.random.rand(1, dim)
    for i in range(1, pop):
        for j in range(dim):
            Z[i, j] = r * Z[i - 1, j] * (1 - Z[i - 1, j])

    X = np.zeros([pop, dim])
    for i in range(pop):
        for j in range(dim):
            # X[i, j] = lb[j] + (ub[j] - lb[j]) * Z[i, j]
            X[i, j] = (lb[j] + ub[j]) / 2 + Z[i, j] * ((ub[j] - lb[j]) / 2)

    return X


'''混沌映射Tent'''


def tentMap(pop, dim, ub, lb,obj_func=None):
    a = 0.499  # （0,1）
    Z = np.zeros([pop, dim])
    Z[0, :] = np.random.rand(1, dim)
    for i in range(1, pop):
        for j in range(dim):
            if Z[i - 1, j] < a:
                Z[i, j] = Z[i - 1, j] / a
            elif Z[i - 1, j] >= a:
                Z[i, j] = (1 - Z[i - 1, j]) / (1 - a)
    # return reverseStudyX(Z, pop, dim, ub, lb, obj_func)
    X = np.zeros([pop, dim])
    for i in range(pop):
        for j in range(dim):
            X[i, j] = lb[j] + (ub[j] - lb[j]) * Z[i, j]
    return X


'''sine混沌映射'''


def sineMap(pop, dim, ub, lb):
    a = 4.0
    Z = np.zeros([pop, dim])
    Z[0, :] = np.random.rand(1, dim)
    for i in range(1, pop):
        for j in range(dim):
            Z[i, j] = np.sin(np.pi * Z[i - 1, j]) * (4 / a)
    X = np.zeros([pop, dim])
    for i in range(pop):
        for j in range(dim):
            X[i, j] = lb[j] + (ub[j] - lb[j]) * Z[i, j]
    return X


'''改进型sine混沌映射'''

'''singer混沌映射'''


def singerMap(pop, dim, ub, lb):
    a = 1.07  # (0.9,1.08)
    Z = np.zeros([pop, dim])
    Z[0, :] = np.random.rand(1, dim)
    for i in range(1, pop):
        for j in range(dim):
            Z[i, j] = a * (7.86 * Z[i - 1, j] - 23.31 * Z[i - 1, j] ** 2 + 28.75 * Z[i - 1, j] ** 3 - 13.302875 * Z[
                i - 1, j] ** 4)
    X = np.zeros([pop, dim])
    for i in range(pop):
        for j in range(dim):
            X[i, j] = lb[j] + (ub[j] - lb[j]) * Z[i, j]
    return X


'''SPM混沌映射'''


def spmMap(pop, dim, ub, lb):
    eta = 0.4  # (0,1)
    u = 0.3  # (0,1)
    Z = np.zeros([pop, dim])
    Z[0, :] = np.random.rand(1, dim)
    for i in range(1, pop):
        for j in range(dim):
            r = np.random.rand()
            if 0 <= Z[i - 1, j] <= eta:
                Z[i, j] = np.mod(Z[i - 1, j] / eta + u * np.sin(np.pi * Z[i - 1, j]) + r, 1)
            elif eta <= Z[i - 1, j] < 0.5:
                Z[i, j] = np.mod((Z[i - 1, j] / eta) / (0.5 - eta) + u * np.sin(np.pi * Z[i - 1, j]) + r, 1)
            elif 0.5 <= Z[i - 1, j] < 1 - eta:
                Z[i, j] = np.mod(((1 - Z[i - 1, j]) / eta) / (0.5 - eta) + u * np.sin(np.pi * (1 - Z[i - 1, j])) + r, 1)
            elif 1 - eta <= Z[i - 1, j] < 1:
                Z[i, j] = np.mod((1 - Z[i - 1, j]) / eta + u * np.sin(np.pi * (1 - Z[i - 1, j])) + r, 1)
    X = np.zeros([pop, dim])
    for i in range(pop):
        for j in range(dim):
            X[i, j] = lb[j] + (ub[j] - lb[j]) * Z[i, j]
    return X


'''Fuch混沌映射'''


def fuchMap(pop, dim, ub, lb):
    Z = np.zeros([pop, dim])
    Z[0, :] = np.random.rand(1, dim)
    for i in range(1, pop):
        for j in range(dim):
            Z[i, j] = np.cos(1 / Z[i - 1, j] ** 2)
    X = np.zeros([pop, dim])
    for i in range(pop):
        for j in range(dim):
            X[i, j] = (lb[j] + ub[j]) / 2 + Z[i, j] * ((ub[j] - lb[j]) / 2)
    return X


'''Chebyshev混沌映射图'''


def chebyshevMap(pop, dim, ub, lb, obj_func=None):
    k = 4
    Z = np.zeros([pop, dim])
    Z[0, :] = np.random.rand(1, dim)
    for i in range(1, pop):
        for j in range(dim):
            Z[i, j] = np.cos(k * np.arccos(Z[i - 1, j]))

    return reverseStudyX(Z, pop, dim, ub, lb, obj_func)


'''Henon混沌映射'''


def henonMap(pop, dim, ub, lb):
    a = 1.4
    b = 0.3
    Z = np.zeros([pop, dim])
    Y = np.zeros([pop, dim])
    Z[0, :] = np.random.rand(1, dim)
    Y[0, :] = np.random.rand(1, dim)
    for i in range(1, pop):
        for j in range(dim):
            Z[i, j] = 1 + Y[i - 1, j] - a * Z[i - 1, j] ** 2
            Y[i, j] = b * Z[i - 1, j]
    X = np.zeros([pop, dim])
    for i in range(pop):
        for j in range(dim):
            X[i, j] = lb[j] + (ub[j] - lb[j]) * Z[i, j]
    return X


'''Sinusoidal混沌映射'''


def sinusoidalMap(pop, dim, ub, lb):
    a = 2.3
    Z = np.zeros([pop, dim])
    Z[0, :] = np.full((1, dim), 0.7)
    for i in range(1, pop):
        for j in range(dim):
            Z[i, j] = a * (Z[i - 1, j] ** 2) * (np.sin(np.pi * Z[i - 1, j]))
    X = np.zeros([pop, dim])
    for i in range(pop):
        for j in range(dim):
            X[i, j] = lb[j] + (ub[j] - lb[j]) * Z[i, j]
    return X


'''circle混沌映射(有问题)'''


def circleMap(pop, dim, ub, lb):
    a = 0.5
    b = 0.2
    Z = np.zeros([pop, dim])
    Z[0, :] = np.random.rand(1, dim)
    for i in range(1, pop):
        for j in range(dim):
            Z[i, j] = np.mod(Z[i - 1, j] + b - ((a / 2 * np.pi) * np.sin(2 * np.pi * Z[i - 1, j])), 1)
    X = np.zeros([pop, dim])
    for i in range(pop):
        for j in range(dim):
            X[i, j] = lb[j] + (ub[j] - lb[j]) * Z[i, j]
    return X


'''Cubic混沌映射'''


def cubicMap(pop, dim, ub, lb):
    p = 2.595
    Z = np.zeros([pop, dim])
    Z[0, :] = np.full((1, dim), 0.3)
    for i in range(1, pop):
        for j in range(dim):
            Z[i, j] = p * Z[i - 1, j] * (1 - Z[i - 1, j] ** 2)
    X = np.zeros([pop, dim])
    for i in range(pop):
        for j in range(dim):
            X[i, j] = lb[j] + (ub[j] - lb[j]) * Z[i, j]
    return X


'''Iterative混沌映射'''


def iterativeMap(pop, dim, ub, lb):
    b = np.random.rand()
    Z = np.zeros([pop, dim])
    Z[0, :] = np.random.rand(1, dim)
    for i in range(1, pop):
        for j in range(dim):
            Z[i, j] = np.sin((b * np.pi) / Z[i - 1, j])
    X = np.zeros([pop, dim])
    for i in range(pop):
        for j in range(dim):
            X[i, j] = lb[j] + (ub[j] - lb[j]) * Z[i, j]
    return X


'''Logistic-tent混沌映射'''


def logisticTentMap(pop, dim, ub, lb, obj_func=None):
    r = 0.1  # 0.3    0.1
    Z = np.zeros([pop, dim])
    Z[0, :] = np.random.rand(1, dim)
    for i in range(1, pop):
        for j in range(dim):
            if Z[i - 1, j] < 0.5:
                Z[i, j] = np.mod(r * Z[i - 1, j] * (1 - Z[i - 1, j]) + (4 - r) * Z[i - 1, j] / 2, 1)
            else:
                Z[i, j] = np.mod(r * Z[i - 1, j] * (1 - Z[i - 1, j]) + (4 - r) * (1 - Z[i - 1, j]) / 2, 1)

    return reverseStudyX(Z, pop, dim, ub, lb, obj_func)

def logisticTentMap2(pop, dim, ub, lb, obj_func=None):
    r = 0.1  # 0.3    0.1
    X = np.zeros([pop, dim])
    X[0, :] = np.random.rand(1, dim)
    for i in range(1, pop):
        for j in range(dim):
            if X[i - 1, j] < 0.5:
                X[i, j] = np.mod(r * X[i - 1, j] * (1 - X[i - 1, j]) + (4 - r) * X[i - 1, j] / 2, 1)
            else:
                X[i, j] = np.mod(r * X[i - 1, j] * (1 - X[i - 1, j]) + (4 - r) * (1 - X[i - 1, j]) / 2, 1)
    rX = np.zeros([pop, dim])
    for i in range(pop):
        for j in range(dim):
            rX[i, j] = lb[j] + ub[j] - X[i, j]
    newX = np.zeros([pop * 2, dim])
    for i in range(pop * 2):
        if i < pop:
            newX[i] = X[i]
        else:
            newX[i] = rX[i - pop]
    fitness = np.zeros([2 * pop, 1])
    for i in range(pop * 2):
        fitness[i] = obj_func(newX[i])

    allY, index = SortFitness(fitness)
    allX = SortPosition(index, newX, pop, dim)

    return allX[:pop], allY[:pop]


'''测试一下'''


def sinMap(pop, dim, ub, lb, obj_func=None):
    Z = np.zeros([pop, dim])
    for i in range(dim):
        num = 0
        while num == 0:
            num = random.uniform(-1, 1)
        Z[0][i] = num
    for i in range(1, pop):
        for j in range(dim):
            Z[i, j] = np.sin(2 / Z[i - 1, j])

    return reverseStudyX(Z, pop, dim, ub, lb, obj_func)



'''适应度排序'''


def SortFitness(Fit):
    fitness = np.sort(Fit, axis=0)
    index = np.argsort(Fit, axis=0)
    return fitness, index


'''根据适应度对位置进行排序'''


def SortPosition(index, X, pop_size, n_dim):
    Xnew = np.zeros([2 * pop_size, n_dim])
    for i in range(2 * pop_size):
        Xnew[i, :] = X[index[i], :]
    return Xnew


def reverseStudyX(Z, pop, dim, ub, lb, obj_func=None):
    '''搭配反向学习初始化'''
    X = np.zeros([pop, dim])
    for i in range(pop):
        for j in range(dim):
            # X[i, j] = lb[j] + (ub[j] - lb[j]) * Z[i, j]
            X[i, j] = (lb[j] + ub[j]) / 2 + Z[i, j] * ((ub[j] - lb[j]) / 2)
    rX = np.zeros([pop, dim])
    for i in range(pop):
        for j in range(dim):
            rX[i, j] = lb[j] + ub[j] - X[i, j]
    newX = np.zeros([pop * 2, dim])
    for i in range(pop * 2):
        if i < pop:
            newX[i] = X[i]
        else:
            newX[i] = rX[i - pop]
    fitness = np.zeros([2 * pop, 1])
    for i in range(pop * 2):
        fitness[i] = obj_func(newX[i])

    allY, index = SortFitness(fitness)
    allX = SortPosition(index, newX, pop, dim)

    return allX[:pop], allY[:pop]


if __name__ == '__main__':
    populationSize = 2000
    dim = 1
    ub = [100]
    lb = [-100]
    X = fuchMap(populationSize, dim, ub, lb)
    drawChart(X, populationSize)
    print('当前x', X)
